package chapter011;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.logging.Logger;

/**
 * 日期工具类
 *
 * @author Jack魏
 */
public class MyDateUtil {

	/**
	 * Java 内置日志类
	 */
	private static Logger logger = Logger.getLogger(MyDateUtil.class.getName());

	public final static String START_HOUR = " 00:00:00";
	public final static String END_HOUR = " 23:59:59";
	/**
	 * 时间间隔：年
	 */
	public final static int DATE_INTERVAL_YEAR = 1;
	/**
	 * 时间间隔：月
	 */
	public final static int DATE_INTERVAL_MONTH = 2;
	/**
	 * 时间间隔：周
	 */
	public final static int DATE_INTERVAL_WEEK = 3;
	/**
	 * 时间间隔：日
	 */
	public final static int DATE_INTERVAL_DAY = 4;
	/**
	 * 时间间隔：小时
	 */
	public final static int DATE_INTERVAL_HOUR = 5;
	/**
	 * 时间间隔：分钟
	 */
	public final static int DATE_INTERVAL_MINUTE = 6;
	/**
	 * 时间间隔：秒
	 */
	public final static int DATE_INTERVAL_SECOND = 7;

	/**
	 * 时间格式   yyyy 是完整的公元年，MM 是月份，dd 是日期，HH:mm:ss 是时、分、秒。
	 * h  A.M./P.M. (1~12)格式小时
	 * S  毫秒数
	 */
	public final static String DATE_FORMAT_YEAR = "yyyy";
	public final static String DATE_FORMAT_MONTH = "MM";
	public final static String DATE_FORMAT_DAY = "dd";
	public final static String DATE_FORMAT_MD = "MM-dd";
	public final static String DATE_FORMAT_HM = "HH:mm";
	public final static String DATE_FORMAT_YM = "yyyy-MM";
	public final static String DATE_FORMAT_YMD = "yyyy-MM-dd";
	public final static String DATE_FORMAT_YMD2 = "yyyyMMdd";
	public final static String DATE_FORMAT_YMDHH = "yyyy-MM-dd HH";
	public final static String DATE_FORMAT_YMDHMS = "yyyy-MM-dd HH:mm:ss";
	public final static String DATE_FORMAT_YMDHMS2 = "yyyyMMddHHmmss";
	public final static String DATE_FORMAT_YMDHMS_XG = "yyyy/MM/dd HH:mm:ss";
	public final static String DATE_FORMAT_YMDHMS_TZ = "yyyy-MM-dd'T'HH:mm:ss'Z'";
	public final static String DATE_FORMAT_YMDHMSsss = "yyyyMMddHHmmssSSS";
	public final static String DATE_FORMAT_YMDHMS_CN = "yyyy年MM月dd HH:mm:ss";
	public final static String DATE_FORMAT_YMDHM_CN = "yyyy年MM月dd HH:mm";
	public final static String DATE_FORMAT_YMD_CN = "yyyy年MM月dd";
	public final static String DATE_FORMAT_MDHM_CN = "MM月dd HH:mm";

	/**
	 * 获得当前日期
	 * 根据 format格式获取当前时间
	 */
	public static Date getNowDate(String format) {
		return dateFormat(dateFormat(new Date(), format), format);
	}

	/**
	 * 获取当前时间字符串
	 * 根据 format格式获取当前时间字符串
	 */
	public static String getNowStringDate(String format) {
		return dateFormat(new Date(), format);
	}

	/**
	 * 获得指定日期字符串格式
	 */
	public static String getStringDate(Date date, String format) {
		return dateFormat(date, format);
	}


	/**
	 * 获取当年的第一天
	 */
	public static Date getCurrYearFirstDate() {
		Calendar currCal = Calendar.getInstance();
		int currentYear = currCal.get(Calendar.YEAR);
		return getYearFirst(currentYear);
	}

	/**
	 * 获取当年的最后一天
	 */
	public static Date getCurrYearLastDate() {
		Calendar currCal = Calendar.getInstance();
		int currentYear = currCal.get(Calendar.YEAR);
		return getYearLast(currentYear);
	}

	/**
	 * 获取某年第一天日期
	 */
	public static Date getYearFirst(int year) {
		Calendar calendar = Calendar.getInstance();
		calendar.clear();
		calendar.set(Calendar.YEAR, year);
		Date currYearFirst = calendar.getTime();
		return currYearFirst;
	}

	/**
	 * 获取某年最后一天日期
	 */
	public static Date getYearLast(int year) {
		Calendar calendar = Calendar.getInstance();
		calendar.clear();
		calendar.set(Calendar.YEAR, year);
		calendar.roll(Calendar.DAY_OF_YEAR, -1);
		Date currYearLast = calendar.getTime();
		return currYearLast;
	}

	/**
	 * 根据日期格式获得时间
	 */
	public static Date getDate(Date date, String dateFormat) {
		return dateFormat(dateFormat(date, dateFormat), dateFormat);
	}

	/**
	 * 根据字符串和日期格式获得时间
	 */
	public static Date getDate(String date, String dateFormat) {
		return dateFormat(date, dateFormat);
	}

	/**
	 * 获取当月第一天
	 */
	public static Date getMonthFirst() {
		Calendar lastDate = Calendar.getInstance();
		// 设为当前月的1号
		lastDate.set(Calendar.DATE, 1);
		return getDate(lastDate.getTime(), DATE_FORMAT_YMD);
	}

	/**
	 * 获得下个月第一天的日期
	 */
	public static Date getNextMonthFirst() {
		Calendar lastDate = Calendar.getInstance();
		// 加一个月
		lastDate.add(Calendar.MONTH, 1);
		// 把日期设置为当月第一天
		lastDate.set(Calendar.DATE, 1);
		return getDate(lastDate.getTime(), DATE_FORMAT_YMD);
	}

	/**
	 * 获取指定日期后一个月的第一天
	 */
	public static Date getNextMonthFirst(Date date) {
		Calendar lastDate = Calendar.getInstance();
		lastDate.setTime(date);
		// 加一个月
		lastDate.add(Calendar.MONTH, 1);
		// 把日期设置为当月第一天
		lastDate.set(Calendar.DATE, 1);
		return getDate(lastDate.getTime(), DATE_FORMAT_YMD);
	}

	/**
	 * 获取指定日期的第一天
	 */
	public static Date getMonthFirst(Date date) {
		Calendar lastDate = Calendar.getInstance();
		lastDate.setTime(date);
		// // 把日期设置为当月第一天
		lastDate.set(Calendar.DATE, 1);
		return getDate(lastDate.getTime(), DATE_FORMAT_YMD);
	}

	/**
	 * 取得当前星期几
	 */
	public static String getWeekOfDate(Date date) {
		String[] weekDays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
		if (w < 0){
			w = 0;
		}
		return weekDays[w];
	}

	/**
	 * 或得当前日期是一年中的第几周
	 */
	public static int getWeekNumOfDate(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		cal.get(Calendar.WEEK_OF_YEAR);
		return cal.get(Calendar.WEEK_OF_YEAR);
	}

	/**
	 * 获取当周第一天
	 */
	public static Date getCurWeekFirst() {
		Calendar lastDate = Calendar.getInstance();
		lastDate.setFirstDayOfWeek(Calendar.MONDAY);
		return getDate(lastDate.getTime(), DATE_FORMAT_YMD);
	}

	/**
	 * 获取当周最后一天
	 */
	public static Date getCurWeekEnd() {
		Calendar lastDate = Calendar.getInstance();
		lastDate.setFirstDayOfWeek(Calendar.SUNDAY);
		lastDate.add(Calendar.DAY_OF_WEEK, 6);
		return getDate(lastDate.getTime(), DATE_FORMAT_YMD);
	}

	/**
	 * 获取指定周的第一天
	 */
	public static Date getWeekFirst(Date date) {
		Calendar lastDate = Calendar.getInstance();
		lastDate.setTime(date);
		int d = 0;
		if (lastDate.get(Calendar.DAY_OF_WEEK) == 1) {
			d = -6;
		} else {
			d = 2 - lastDate.get(Calendar.DAY_OF_WEEK);
		}
		lastDate.add(Calendar.DAY_OF_WEEK, d);
		return getDate(lastDate.getTime(), DATE_FORMAT_YMD);
	}

	/**
	 * 获取指定周的最后一天
	 */
	public static Date getWeekEnd(Date date) {
		Calendar lastDate = Calendar.getInstance();
		lastDate.setTime(date);
		int d = 0;
		if (lastDate.get(Calendar.DAY_OF_WEEK) == 1) {
			d = -6;
		} else {
			d = 2 - lastDate.get(Calendar.DAY_OF_WEEK);
		}
		lastDate.add(Calendar.DAY_OF_WEEK, d);
		lastDate.add(Calendar.DAY_OF_WEEK, 6);
		return getDate(lastDate.getTime(), DATE_FORMAT_YMD);
	}

	/**
	 * 时间类型转换返回字符串
	 */
	public static String dateFormat(Date date, String dateFormat) {
		SimpleDateFormat format = new SimpleDateFormat(dateFormat);
		return format.format(date);
	}

	/**
	 * 字符串时间类型转换返回Date类型
	 */
	public static Date dateFormat(String date, String dateFormat) {
		SimpleDateFormat format = new SimpleDateFormat(dateFormat);
		try {
			return format.parse(date);
		} catch (Exception e) {
			logger.severe("格式化日期出错: " + e.getMessage());
			return null;
		}
	}

	/**
	 * 加时间
	 * interval 年, 月, 日, 周, 时, 分, 秒
	 * date 开始日期
	 * num 加减多少
	 */
	public static Date dateAdd(int interval, Date date, int num) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		switch (interval) {
			case DATE_INTERVAL_YEAR:
				calendar.add(Calendar.YEAR, num);
				break;
			case DATE_INTERVAL_MONTH:
				calendar.add(Calendar.MONTH, num);
				break;
			case DATE_INTERVAL_WEEK:
				calendar.add(Calendar.WEEK_OF_MONTH, num);
				break;
			case DATE_INTERVAL_DAY:
				calendar.add(Calendar.DATE, num);
				break;
			case DATE_INTERVAL_HOUR:
				calendar.add(Calendar.HOUR, num);
				break;
			case DATE_INTERVAL_MINUTE:
				calendar.add(Calendar.MINUTE, num);
				break;
			case DATE_INTERVAL_SECOND:
				calendar.add(Calendar.SECOND, num);
				break;
			default:
		}
		return calendar.getTime();
	}

	/**
	 * 两个时间时间差
	 *     前面时间和比较时间比 小于比较时间返回负数
	 *  interval 比较项 年, 月, 日, 周, 时, 分, 秒
	 *  date  时间
	 *  compare  比较的时间
	 * @return 时间差(保留两位小数点,小数点以后两位四舍五入)
	 */
	public static double getDateDiff(int interval, Date date, Date compare) {
		double result = 0;
		double time = 0;
		Calendar calendar = null;
		switch (interval) {
			case DATE_INTERVAL_SECOND:
				time = date.getTime() - compare.getTime();
				result = time / 1000d;
				break;
			case DATE_INTERVAL_MINUTE:
				time = date.getTime() / 1000d / 60d;
				result = time - compare.getTime() / 1000d / 60d;
				break;
			case DATE_INTERVAL_HOUR:
				time = date.getTime() - compare.getTime();
				result = time / 1000d / 60d / 60d;
				break;
			case DATE_INTERVAL_DAY:
				time = date.getTime() - compare.getTime();
				result = time / 1000d / 60d / 60d / 24d;
				break;
			case DATE_INTERVAL_WEEK:
				calendar = Calendar.getInstance();
				calendar.setTime(date);
				time = calendar.get(Calendar.YEAR) * 52d;
				calendar.setTime(compare);
				time -= calendar.get(Calendar.YEAR) * 52d;
				calendar.setTime(date);
				time += calendar.get(Calendar.WEEK_OF_YEAR);
				calendar.setTime(compare);
				result = time - calendar.get(Calendar.WEEK_OF_YEAR);
				break;
			case DATE_INTERVAL_MONTH:
				calendar = Calendar.getInstance();
				calendar.setTime(date);
				time = calendar.get(Calendar.YEAR) * 12d;
				calendar.setTime(compare);
				time -= calendar.get(Calendar.YEAR) * 12d;
				calendar.setTime(date);
				time += calendar.get(Calendar.MONTH);
				calendar.setTime(compare);
				result = time - calendar.get(Calendar.MONTH);
				break;
			case DATE_INTERVAL_YEAR:
				calendar = Calendar.getInstance();
				calendar.setTime(date);
				time = calendar.get(Calendar.YEAR);
				calendar.setTime(compare);
				result = time - (double) calendar.get(Calendar.YEAR);
				break;
			default:
				break;
		}
		return new BigDecimal(result).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	/**
	 * 时间是否合法
	 */
	public static boolean isValidDate(String date, String dateFormat) {
		try {
			new SimpleDateFormat(dateFormat).parse(date);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	static int[] monthDay = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

	/**
	 * 根据年月获取这个月的天数
	 */
	public static int getMonthDays(String date) {
		String year = date.split("-")[0];
		String month = date.split("-")[1];
		int y = Integer.parseInt(year);
		int m = Integer.parseInt(month);
		if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) {
			if (m == 2) {
				return 29;
			} else {
				return monthDay[m - 1];
			}
		} else {
			return monthDay[m - 1];
		}
	}

	/**
	 * 当前时间加减多少天
	 */
	public static String getStringAddOrSubDay(long day) {
		LocalDateTime today = LocalDateTime.now(ZoneOffset.of("+8"));
		if (day > 0) {
			today = today.plusDays(day);
		} else {
			today = today.minusDays(day * -1);
		}
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		return today.format(formatter);
	}

	/**
	 * 根据日期加减多少天
	 */
	public static String getStringAddOrSubDay(LocalDateTime date, long day) {
		if (day > 0) {
			date = date.plusDays(day);
		} else {
			date = date.minusDays(day * -1);
		}
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		return date.format(formatter);
	}

	/**
	 * Date 转String “yyyy-MM-dd”
	 */
	public static String getStringDate(Date date) {
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		return formatter.format(date);
	}

	/**
	 * 获取本周的开始时间
	 */
	@SuppressWarnings("unused")
	public static String getBeginDayOfWeek() {
		Date date = new Date();
		if (date == null) {
			return null;
		}
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int dayofweek = cal.get(Calendar.DAY_OF_WEEK);
		if (dayofweek == 1) {
			dayofweek += 7;
		}
		cal.add(Calendar.DATE, 2 - dayofweek);
		return getStringDate(cal.getTime());
	}

	/**
	 * 获取本周的结束时间
	 */
	public static String getEndDayOfWeek() {
		Calendar cal = Calendar.getInstance();
		cal.setTime(dateFormat(getBeginDayOfWeek(), DATE_FORMAT_YMDHMS));
		cal.add(Calendar.DAY_OF_WEEK, 6);
		Date weekEndSta = cal.getTime();
		return getStringDate(weekEndSta);
	}

	/**
	 * 获取当前季度开始时间
	 */
	public static String getBeginDayOfQuarter() {
		Calendar c = Calendar.getInstance();
		int currentMonth = c.get(Calendar.MONTH) + 1;
		SimpleDateFormat longSdf = new SimpleDateFormat(DATE_FORMAT_YMDHMS);
		SimpleDateFormat shortSdf = new SimpleDateFormat(DATE_FORMAT_YMD);
		Date now = null;
		try {
			switch (currentMonth) {
			case 1:
			case 2:
			case 3:
				c.set(Calendar.MONTH, 0);
				break;
			case 4:
			case 5:
			case 6:
				c.set(Calendar.MONTH, 3);
				break;
			case 7:
			case 8:
			case 9:
				c.set(Calendar.MONTH, 4);
				break;
			case 10:
			case 11:
			case 12:
				c.set(Calendar.MONTH, 9);
				break;
			}
			c.set(Calendar.DATE, 1);
			now = longSdf.parse(shortSdf.format(c.getTime()) + START_HOUR);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return getStringDate(now);
	}

	/**
	 * 获取当前季度结束时间
	 */
	public static String getEndDayOfQuarter() {
		Calendar cal = Calendar.getInstance();
		cal.setTime(dateFormat(getBeginDayOfQuarter(), DATE_FORMAT_YMDHMS));
		cal.add(Calendar.MONTH, 3);
		return getStringDate(cal.getTime());
	}

	/**
	 * 指定时间段内的每一天
	 */
	public static List<Date> findDates(Date dBegin, Date dEnd) {
		List<Date> dateList = new ArrayList<Date>();
		dateList.add(dBegin);
		Calendar calBegin = Calendar.getInstance();
		// 使用给定的 Date 设置此 Calendar 的时间
		calBegin.setTime(dBegin);
		Calendar calEnd = Calendar.getInstance();
		// 使用给定的 Date 设置此 Calendar 的时间
		calEnd.setTime(dEnd);
		// 测试此日期是否在指定日期之后
		while (dEnd.after(calBegin.getTime())) {
			// 根据日历的规则，为给定的日历字段添加或减去指定的时间量
			calBegin.add(Calendar.DAY_OF_MONTH, 1);
			dateList.add(calBegin.getTime());
		}
		return dateList;
	}
}